/**
 * inspectsensor.c
 */

#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <stdio.h>

#include <Ipc.h>
#include <Base.h>

#include "alarmInterlock.h"
#include "alarmInspectsensor.h"

#include "jze/alarmMsg.h"
#include <capturer.h>
extern int msgid;

bool isSensorAlarm(int gpioFD, Sensor *pSensor) {
	bool alarm = false;
	bool level;
	struct timespec jitterTime = {0, GPIO_JITTER_NS};
	GPIOInPin inPin = getGPIOInPinEnum(pSensor->conf.addr);

	if (getGPIOPinVal(gpioFD, inPin, &level)) {	// have this sensor and get pin value success
		// LOGINFO("conf.addr = %d, inPin = %d, conf.level = %d, level = %d\n", pSensor->conf.addr, inPin, pSensor->conf.level, level);
		if (pSensor->conf.level == (char) level) {
			nanosleep(&jitterTime, NULL);	// jitter check
			if (pSensor->conf.level == (char) level && isCurrInSchemeListRange(pSensor->pSchemeList)) {	// in sche time
				alarm = true;
			}
		}
	}

	return alarm;
}

bool isSensorListAlarm(int gpioFD, Sensor *pList) {
	bool alarm = false;
	Sensor *pSensor = pList;

	while (pSensor != NULL) {
		if (isSensorAlarm(gpioFD, pList)) {
			alarm = true;
			break;
		}
		pSensor = pSensor->pNext;
	}

	return alarm;
}


int timerCreate(int seconds,   int value, void *func)
{
    timer_t  tid;
    struct   sigevent se;
    struct   itimerspec ts, ots;
    memset (&se, 0, sizeof (se));
    se.sigev_notify = SIGEV_THREAD;
    se.sigev_notify_function = func;
    se.sigev_value.sival_int = value;
    if (timer_create (CLOCK_REALTIME, &se, &tid) < 0) {
        perror ("timer_creat");
        return   -1;
    }
    LOGINFO("timer_create   successfully.\n");
    ts.it_value.tv_sec = seconds;
    ts.it_value.tv_nsec = 5000;
    ts.it_interval.tv_sec = 0;
    ts.it_interval.tv_nsec = 0;
    if (timer_settime (tid, 0, &ts, &ots)  <   0) {
        perror("timer_settime");
        return -1;
    }
    return 0;
}

void inspectAlarm(sigval_t v)
{
    Sensor  *pSensor = (Sensor *)v.sival_int;
    bool alarm = isSensorAlarm(g_gpioFD, pSensor);
    dbg("hello addr = %d,alarm = %d,pSensor->alarming = %d",pSensor->conf.addr,alarm,pSensor->alarming);
    if( alarm == pSensor->alarming ) {
        time_t  almTime;
        time(&almTime);
        struct tm *pTime = gmtime(&almTime);
        unsigned int act = getInt(pSensor->conf.aActions);
        sendAlmMsg(msgid, pSensor->conf.addr, MM_EXTERN_MASK, act & AA_SNAP_SHOT_MASK, ALARM_TYPE_DEACTIVE, pSensor->conf.snapChn, pTime);
    }
}

void inspectSensor(int msgId, char alarmMsgMask, int gpioFD, Sensor *pSensorList, Capturer *pCapList,int recSecond,struct almtime *almTimer) {
    time_t  almTime;
    Sensor  *pSensor = pSensorList;
    for (;pSensor != NULL;pSensor = pSensor->pNext ) {

        if(!pSensor->conf.enable)
            continue;

        bool    alarm = isSensorAlarm(gpioFD, pSensor);
        int32   index = pSensor->conf.addr - 1;
        // alarm status change
        if (alarm != pSensor->alarming) {
            pSensor->alarming = alarm;
            time(&almTime);
            struct tm *pTime = gmtime(&almTime);
            LOGINFO("addr = %d alarm change to %s\n", pSensor->conf.addr, pSensor->alarming ? "active" : "deactive");
            unsigned int act = getInt(pSensor->conf.aActions);

            almTimer[index].outDelay = 0/*getShort(pSensor->conf.aSLDelays) */;
            almTimer[index].sensitivity = 1;
            pSensor->conf.slAddr = 3;
            // interlock
            if (pSensor->alarming) {
                almTimer[index].alarming = pSensor->alarming;
                dbg(" on : diff %f,",difftime(time(&almTimer[index].startTime),almTimer[index].endTime) );
                if( /*almTimer[index].sensitivity != 0 && */!almTimer[index].alarmCancel
                    && ( ( difftime(time(&almTimer[index].startTime),almTimer[index].endTime) <= almTimer[index].sensitivity ) )/*(double)getShort(pSensor->conf.aSLDelays)*/ ) {
                    LOGINFO("out of wobble.\n");
                    continue;
                }

                if (act & AA_RECORD_MASK) {
                    startAlmRec(msgId, pCapList, pSensor->conf.recId,(char)getShort(pSensor->conf.aRecordDelays) ,recSecond);
                    LOGINFO("will alarm record\n");
                }

                if (act & AA_SNAP_SHOT_MASK) {
                    startSnapShot(msgId, pSensor->conf.snapChn, pSensor->conf.snapInterSec, pTime);
                    LOGINFO("will alarm snapshot\n");
                }

                if( act & AA_PTZ_MASK ) {
                    pSensor->conf.panTiltType = 3;
                    pSensor->conf.panTiltAddr = 1;
                    startPtzCmd(msgId,pSensor->conf.addr - 1 ,pSensor->conf.panTiltType, pSensor->conf.panTiltAddr ,0);
                }
                // TODO: add more AA_XXX_MASK

            } else {
                time(&almTimer[index].endTime);
                dbg(" off : start %f,",(double)almTimer[index].endTime);
                if( alarmMsgMask & MM_EXTERN_MASK ) {
                    //timerCreate(almTimer[index].sensitivity, (int)pSensor, inspectAlarm);
                }
            }

            // need send alarm message
            /*if ( (alarmMsgMask & MM_EXTERN_MASK)
                && almTimer[index].sensitivity == 0 ) {
                //almTimer[index].alarmCancel = false;
                sendAlmMsg(msgId, pSensor->conf.addr, MM_EXTERN_MASK, act & AA_SNAP_SHOT_MASK, pSensor->alarming ? ALARM_TYPE_ACTIVE : ALARM_TYPE_DEACTIVE, pSensor->conf.snapChn, pTime);
            }*/
        }
        //pSensor = pSensor->pNext;
    }
}

